package com.deng.api.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.deng.api.dto.MenuDTO;
import com.deng.api.entity.SysMenu;
import com.deng.api.entity.SysRoleMenu;
import com.deng.api.mapper.SysMenuMapper;
import com.deng.api.mapper.SysRoleMenuMapper;
import com.deng.api.service.ISysMenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deng.api.vo.PageVO;
import com.deng.commons.common.BaseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统菜单 服务实现类
 * </p>
 *
 * @author deng
 * @since 2022-08-10
 */
@Service
@Slf4j
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {
    @Resource
    private SysMenuMapper sysMenuMapper;
    @Resource
    private SysRoleMenuMapper sysRoleMenuMapper;

    @Override
    public List<SysMenu> getMenusByRid(Long rid) {
        return sysMenuMapper.getMenusByRid(rid);
    }

    @Override
    public List<SysMenu> getAllMenus() {
        return sysMenuMapper.getAllMenus();
    }

    @Override
    public BaseResult getMenusByPid(Long pid) {
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        // 如果pid不为空和0，那么返回子菜单
        if (pid != null && !pid.equals(0L)) {
            wrapper.eq(SysMenu::getPid,pid);
        } else {//返回一级菜单
            wrapper.isNull(SysMenu::getPid);
        }
        List<SysMenu>  menuList = sysMenuMapper.selectList(wrapper);
        //把Menu转换为MenuDTO
        List<MenuDTO> dtos = menuList.stream().map(MenuDTO::toDTO).collect(Collectors.toList());
        return BaseResult.success(dtos);
    }

    @Override
    public BaseResult getMenuByRid(Long rid) {
        LambdaQueryWrapper<SysRoleMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysRoleMenu::getRoleId,rid);
        List<SysRoleMenu> rolesMenus = sysRoleMenuMapper.selectList(wrapper);
        //只获取id即可
        List<Long> ids = rolesMenus.stream().map(rm -> rm.getMenuId()).collect(Collectors.toList());
        return BaseResult.success(ids);
    }

    @Override
    public BaseResult getChildren(Long pid) {
        Set<Long> ids = new HashSet<>();
        //根据pid获取它的所有子菜单
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysMenu::getPid,pid);
        List<SysMenu>  menuList = sysMenuMapper.selectList(wrapper);
        //需要使用递归把子菜单的子菜单也获取到
        getChild(menuList,ids);
        ids.add(pid);
        return BaseResult.success(ids);
    }

    @Override
    public PageVO getMenus(Integer page, Integer size, Long pid) {
        Page<SysMenu> p = new Page<>(page,size);
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        //查询一级菜单
        if (pid == null || pid.equals(0L)){
            wrapper.isNull(SysMenu::getPid);
        }else{
            wrapper.eq(SysMenu::getPid,pid);
        }
        Page<SysMenu> menuPage = sysMenuMapper.selectPage(p, wrapper);
        //把Menu转换为MenuDTO
        List<MenuDTO> dtos = menuPage.getRecords().stream()
                .map(MenuDTO::toDTO).collect(Collectors.toList());
        return new PageVO<>(dtos,menuPage.getTotal());
    }

    @Override
    public boolean adds(SysMenu sysMenu) {
        //查看要添加的菜单名是否存在
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysMenu::getTitle,sysMenu.getTitle());
        List<SysMenu> menuList = sysMenuMapper.selectList(wrapper);
        if (menuList != null && menuList.size()>0){
            return false;
        }
        //看是否添加的是一级菜单（目录、菜单、按钮）
        if (sysMenu.getPid().equals(0L)){
            sysMenu.setPid(null);
        }
        //通过iframe看看是否是外联地址校验
        if (sysMenu.getIframe()){
            String http="http://";
            String https="https://";
            if (!StrUtil.isEmptyIfStr(sysMenu.getPath()) &&
                    (sysMenu.getPath().toLowerCase().startsWith(http) || sysMenu.getPath().toLowerCase().startsWith(https))
            ){
            }else{
                return false;
            }
        }
        //把menu添加到数据库中
        sysMenuMapper.insert(sysMenu);
        //更新父级菜单sub_count
        if (sysMenu.getPid() != null){
            QueryWrapper<SysMenu> w = new QueryWrapper<>();
            w.eq("pid",sysMenu.getPid());
            Integer count = sysMenuMapper.selectCount(w);
            //更新数量
            SysMenu menu = new SysMenu();
            menu.setPid(sysMenu.getPid());
            menu.setSubCount(count);
            sysMenuMapper.updateById(menu);
        }
        return true;
    }

    @Override
    public List<MenuDTO> getSuperior(Set<Long> ids) {
        if (ids !=null && ids.size()>0){
            List<MenuDTO> list = new ArrayList<>();
            ids.forEach(id->{
                getSuper(list, id);
            });
            return list;
        }
        return null;
    }

    @Override
    public boolean editMenu(SysMenu sysMenu) {
        //更新菜单的父菜单不能是自己
        if (sysMenu.getId().equals(sysMenu.getPid())){
            return false;
        }
        //如果是一级菜单，那么pid设置null
        if (sysMenu.getPid().equals(0L)){
            sysMenu.setPid(null);
        }
        //还得看修改的标题是否已经存在，修改的菜单也不是自己的时候才冲突
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        SysMenu m = sysMenuMapper.selectOne(wrapper.eq(SysMenu::getTitle,sysMenu.getTitle()));
        if (m != null && !m.getId().equals(sysMenu.getId())){
            log.info("-----修改的菜单标题已经存在");
            return false;
        }
        //更新菜单数据到数据库中
        sysMenuMapper.updateById(sysMenu);
        //更新旧父级sub_count，新父级sub_count
        //旧父级sub_count
        SysMenu oldMenu = sysMenuMapper.selectById(sysMenu.getId());
        updateCount(oldMenu.getPid());
        //新父级sub_count
        updateCount(sysMenu.getPid());
        return true;
    }

    @Override
    public boolean deleteMenu(Set<Long> ids) {
        if (ids != null && ids.size()>0){
            //解除角色和菜单关系，sys_roles_menus中删除绑定关系
            LambdaUpdateWrapper<SysRoleMenu> wrapper = new LambdaUpdateWrapper<>();
            wrapper.in(SysRoleMenu::getMenuId,ids);
            sysRoleMenuMapper.delete(wrapper);
            //删除菜单
            sysMenuMapper.deleteBatchIds(ids);
            //更新sub_count数量
            List<SysMenu> menus = sysMenuMapper.selectBatchIds(ids);
            menus.forEach(menu -> updateCount(menu.getPid()));
            return true;
        }
        return false;
    }

    private void getSuper(List<MenuDTO> list, Long id) {
        // 1.通过ID获取当前菜单信息
        SysMenu sysMenu = sysMenuMapper.selectById(id);
        list.add(MenuDTO.toDTO(sysMenu));
        // 2.通过pid 判断是获取所有的一级菜单还是所有的父级菜单信息
        if (sysMenu.getPid() == null || sysMenu.getPid().equals(0L)){
            //获取所有的一级菜单
            LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
            wrapper.isNull(SysMenu::getPid);
            List<SysMenu> menus = sysMenuMapper.selectList(wrapper);
            List<MenuDTO> dtos = getDTOS(menus);
            list.addAll(dtos);
            return ;
        }else{
            //获取父级
            getSuper(list,sysMenu.getPid());
        }
    }
    /**
     * 更新sub_count数量
     * @param pid
     */
    public void updateCount(Long pid){
        Integer count = sysMenuMapper.selectCount(
                new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getPid,pid));
        SysMenu sysMenu = new SysMenu();
        sysMenu.setPid(pid);
        sysMenu.setSubCount(count);
        sysMenuMapper.updateById(sysMenu);
    }

    public List<MenuDTO> getDTOS(List<SysMenu> menus){
        //把Menu转换为MenuDTO
        return menus.stream().map(MenuDTO::toDTO).collect(Collectors.toList());
    }

    public void getChild(List<SysMenu> menus,Set<Long> ids){
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        menus.forEach(menu -> {
            ids.add(menu.getId());
            //把menu_id当成pid去查找看看有没有数据，有数据就有子菜单
            wrapper.eq(SysMenu::getPid,menu.getId());
            List<SysMenu> menuList = sysMenuMapper.selectList(wrapper);
            if (menuList != null && menuList.size()>0){
                getChild(menuList,ids);
            }
        });
    }

}
